package com.spyx.activity.service.impl;

import com.atyx.spyx.enums.CouponRangeType;
import com.atyx.spyx.model.activity.CouponInfo;
import com.atyx.spyx.model.activity.CouponRange;
import com.atyx.spyx.model.order.CartInfo;
import com.atyx.spyx.model.product.Category;
import com.atyx.spyx.model.product.SkuInfo;
import com.atyx.spyx.vo.activity.CouponRuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spyx.activity.mapper.CouponInfoMapper;
import com.spyx.activity.mapper.CouponRangeMapper;
import com.spyx.activity.service.CouponInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spyx.product.ProductClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券信息 服务实现类
 * </p>
 *
 * @author yhp
 * @since 2024-05-21
 */
@Service
public class CouponInfoServiceImpl extends ServiceImpl<CouponInfoMapper, CouponInfo> implements CouponInfoService {

    @Override
    public IPage<CouponInfo> selectList(Page p1) {
        IPage<CouponInfo> pageModel = baseMapper.selectPage(p1,null);
        //设置优惠券的类型
        List<CouponInfo> records = pageModel.getRecords();
        for (CouponInfo record : records) {
            record.setCouponTypeString(record.getCouponType().getComment());
        }
        return pageModel;
    }

    @Autowired
    private CouponRangeMapper couponRangeMapper;

    @Autowired
    private ProductClient productClient;
    @Override
    public Map<String, Object> findCouponRuleList(Integer id) {

        //1.创建Map对象
        Map map=new HashMap();
        //2.根据优惠券id,查询优惠券的基本信息
        CouponInfo couponInfo = baseMapper.selectById(id);
        //3.根据优惠券iD,查询优惠券使用范围表: coupon_range,获取到了优惠券的使用范围类型-range_type
        LambdaQueryWrapper<CouponRange> wrapper = new LambdaQueryWrapper<CouponRange>();
        wrapper.eq(CouponRange::getCouponId,id);
        List<CouponRange> couponRangeList = couponRangeMapper.selectList(wrapper);
        //说明: range_id 表示的含义会因为range_type的值不同而不同
        // range_type=2 此时的range_id 表示类型的id值(category表的id)
        // range_type=1 此时的range_id 表示的SKU的id值(sku_info表的id)
        //4.根据范围类型值range_type，判断是查询sku的信息还是分类的信息
        //4.1 提取 couponRangeList中的range_id的值
        List<Long> idslist = couponRangeList.stream().map(CouponRange::getRangeId).collect(Collectors.toList());
        //4.2 根据优惠券的类型判断idslist表示的是sku的id还是category的id
        if(couponInfo.getRangeType()== CouponRangeType.SKU){
            //idslist代表的是skuid值，接下来查询sku表
            List<SkuInfo> skuInfoList = productClient.getskuInfoListbyids(idslist);
            map.put("skuInfoList",skuInfoList);
        }else if(couponInfo.getRangeType()==CouponRangeType.CATEGORY){
            //idslist代表的是Category的id值，接下来查询category表
            List<Category> categoryList = productClient.getcategoryListbyids(idslist);
            map.put("categoryList",categoryList);
        }else{
            //TODO 查询通用情况下的数据
        }

        return map;
    }

    @Override  //这个功能涉及到两表的数据操作
    public void saveRule(CouponRuleVo vo) {
        //1.先保存CouponInfo中的数据-本质上是更新操作
       //1.1 根据优惠券id,查询优惠券对象信息
        Long couponId = vo.getCouponId();
        CouponInfo couponInfo = baseMapper.selectById(couponId);
        //1.2 将前端传递来的数据覆盖
        couponInfo.setRangeType(vo.getRangeType());
        couponInfo.setAmount(vo.getAmount());
        couponInfo.setConditionAmount(vo.getConditionAmount());
        couponInfo.setRangeDesc(vo.getRangeDesc());
        //1.3 保存(更新操作)
        baseMapper.updateById(couponInfo);
       //2.保存优惠券使用范围表
       //2.1 根据优惠券的iD,删除优惠券使用范围表中的数据
        LambdaQueryWrapper<CouponRange> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CouponRange::getCouponId,couponId);
        couponRangeMapper.delete(wrapper);
       //2.2 新增新的优惠券使用范围
        List<CouponRange> couponRangeList = vo.getCouponRangeList();
        for (CouponRange couponRange : couponRangeList) {
            couponRange.setCouponId(couponId);
            couponRangeMapper.insert(couponRange);
        }


    }


    @Override
    public List<CouponInfo> findCouponByKeyword(String keyword) {
        LambdaQueryWrapper<CouponInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(CouponInfo::getCouponName,keyword);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<CouponInfo> findCouponInfo(Long userId, Long skuId) {
        //1.如果的range_type=1 表示rang_id是skuid,
        // 如果range_type=2 表示range_id是categoryid
        //1.由于rang_id的值一会是skuid,一会categoryid,但是现在已经有的条件:skuid
        // 解决方案: 远程调取service-product中的方法: 根据skuid,查询skuinfo信息(skuid,categoryid)
        SkuInfo skuInfo = productClient.findById(skuId);
        if(skuInfo==null){
            return new ArrayList<>();
        }
        //2.获取skuInfo中的id和categoryid
        Long categoryId = skuInfo.getCategoryId();
        List<CouponInfo> couponInfoList=
               baseMapper.selectCouponInfoList(userId,skuId,categoryId);
        //3.将查询结果返回

        return couponInfoList;
    }

    @Override
    public List<CouponInfo> findCartCouponInfo(List<CartInfo> cartInfoList, Long userId) {
        //1.根据用户id,获取该用户的全部的优惠券
        List<CouponInfo> userAllCouponInfoList = baseMapper.selectCartCouponInfoList(userId);
        //2.根据上一步返回的优惠券列表，获取优惠券id
        if(CollectionUtils.isEmpty(userAllCouponInfoList)){
            return null;
        }
        List<Long> couponIdList = userAllCouponInfoList.stream().map(couponInfo -> couponInfo.getId()).collect(Collectors.toList());
        //3.根据优惠券ID查询优惠券各自的使用范围-coupon_range -使用in查询
        LambdaQueryWrapper<CouponRange> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(CouponRange::getCouponId,couponIdList);
        List<CouponRange> couponRangeList = couponRangeMapper.selectList(wrapper);
        //4. 获取优惠券id及其对应的skuid列表  map key=优惠券id  value=skuid列表
        //参数: 购物车商品列表   优惠券活动规则列表
        Map<Long,List<Long>> couponIdToSkuIdMap=this.findCouponIdToSkuIdMap(cartInfoList, couponRangeList);
        //5.遍历全部的优惠券集合，判断优惠券类型(通用和不通用)
        BigDecimal reduceAmount = new BigDecimal("0");//保存当前的优惠金额（实际减少的金额）
         CouponInfo optimalCouponInfo=null;//保存最优的优惠券对象
        for (CouponInfo couponInfo : userAllCouponInfoList) {
            if(couponInfo.getRangeType()==CouponRangeType.ALL){
                    //优惠券通用
                //计算购物车商品的总金额
                BigDecimal totalAmount = this.computeTotalAmount(cartInfoList);
                //只有优惠金额小于总金额的优惠券才能被选中  ConditionAmount 使用该优惠券时的门槛金额
                if(totalAmount.subtract(couponInfo.getConditionAmount()).doubleValue()>=0){
                        couponInfo.setIsSelect(1);//表示该优惠券可以使用
                }
            }else{
                    //优惠券不通用
                   //5.1 获取该优惠券可以使用的skuid
                List<Long> skuidList = couponIdToSkuIdMap.get(couponInfo.getId());
                //5.2 根据skuid，查询商品列表信息
               List<CartInfo> currentCartInfoList = cartInfoList.stream()
                        .filter(cartInfo -> skuidList.contains(cartInfo.getSkuId()))
                        .collect(Collectors.toList());
                //5.3 计算当前商品的总金额
                BigDecimal currentTotalAmount = computeTotalAmount(currentCartInfoList);
                if(currentTotalAmount.subtract(couponInfo.getConditionAmount()).doubleValue()>=0){
                    couponInfo.setIsSelect(1);//表示该优惠券可以使用
                }
            }
            //5.4 计算最有优惠券
            if(couponInfo.getIsSelect().intValue()==1&&
                couponInfo.getAmount().subtract(reduceAmount).doubleValue()>0){ //优惠券优惠金额-之前优惠中的优惠金额
                    reduceAmount=couponInfo.getAmount();  //得到最优的优惠金额
                    optimalCouponInfo=couponInfo;//保存最优的优惠券对象
            }
        }

        //6.判断是否存在最优的优惠券
        if(optimalCouponInfo!=null){
            optimalCouponInfo.setIsOptimal(1); //设置 是否最优选项
        }

        return userAllCouponInfoList;
    }

    private BigDecimal computeTotalAmount(List<CartInfo> cartInfoList) {
        BigDecimal total = new BigDecimal("0");
        for (CartInfo cartInfo : cartInfoList) {
            //是否选中
            if(cartInfo.getIsChecked().intValue() == 1) {
                BigDecimal itemTotal = cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum()));
                total = total.add(itemTotal);
            }
        }
        return total;
    }

    private Map<Long, List<Long>> findCouponIdToSkuIdMap(List<CartInfo> cartInfoList, List<CouponRange> couponRangeList) {
        //1.创建Map集合，封装最终的结果 map key=优惠券id, value=skuid
        Map<Long, List<Long>> couponIdToSkuIdMap = new HashMap<>();
        //2.根据优惠券id分组，得到优惠券的适用范围，key=优惠券id, value=使用范围
        Map<Long, List<CouponRange>> coupouIdMapCouponRangeList =
                couponRangeList.stream().collect(Collectors.groupingBy(CouponRange::getCouponId));
        //3.遍历map集合，最终获取每张优惠券对应的skuid
        Set<Long> CouponIdkeySet = coupouIdMapCouponRangeList.keySet();
        for (Long couponId : CouponIdkeySet) {
            List<CouponRange> couponRanges = coupouIdMapCouponRangeList.get(couponId);//每张优惠券的优惠范围
            //创建set集合，保存skuid的值
            Set skuidSet=new HashSet();
            for (CartInfo cartInfo : cartInfoList) { //遍历购物车中的商品列表
                for (CouponRange couponRange : couponRangeList) {  //优惠券的使用范围
                    //判断优惠券的使用类型
                    if(couponRange.getRangeType()==CouponRangeType.SKU&&  //判断使用范围是否是sku
                        cartInfo.getSkuId().intValue()==couponRange.getRangeId().intValue()){    //在众多购物车商品中判断属于该类型的商品id
                                skuidSet.add(cartInfo.getSkuId().intValue());
                    }else if(couponRange.getRangeType()==CouponRangeType.CATEGORY&& //判断range_type=商品类型
                                cartInfo.getCategoryId().intValue()==couponRange.getRangeId().intValue()){
                        skuidSet.add(cartInfo.getSkuId().intValue());
                    }else{
                        //全场通用
                    }
                }
            }
            //将查询出的skuid存储到map集合
            couponIdToSkuIdMap.put(couponId,new ArrayList<>(skuidSet));
        }

        return couponIdToSkuIdMap;
    }

    @Override   //查看某张优惠券适用的商品id和优惠券信息
    public CouponInfo findRangeSkuIdList(List<CartInfo> cartInfoList, Long couponId) {
        //1.获取couponInfo对象
        CouponInfo couponInfo = this.getById(couponId);
        //2.获取优惠券对应的商品id(skuid)列表
        //2.1 获取某张优惠券的使用范围(使用规则)-couponRangeMapper
        LambdaQueryWrapper<CouponRange> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CouponRange::getCouponId,couponId);
        List<CouponRange> couponRangeList = couponRangeMapper.selectList(wrapper);
        //2.2 根据优惠券使用范围和购物车商品列表的数据，筛选出优惠券和skuid匹配的map集合
        //map  key=优惠券id  value=skuidList
        Map<Long, List<Long>> couponIdToSkuIdMap = this.findCouponIdToSkuIdMap(cartInfoList, couponRangeList);
        //3.将商品列表的集合封装到couponInfo中
     //   List<Long> skuIdList = couponIdToSkuIdMap.entrySet().iterator().next().getValue();
        Iterator<Map.Entry<Long, List<Long>>> iterator = couponIdToSkuIdMap.entrySet().iterator();
        List<Long> skuIdList =new ArrayList<>();
        while(iterator.hasNext()){
            skuIdList = iterator.next().getValue();
            couponInfo.setSkuIdList(skuIdList);
        }
        /*Set<Map.Entry<Long, List<Long>>> entries = couponIdToSkuIdMap.entrySet();
        Iterator<Map.Entry<Long, List<Long>>> iterator = entries.iterator();
        while(iterator.hasNext()){
            iterator.next().getValue();
        }*/
        return couponInfo;
    }
}
